package com.hu.pk.patroller.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ding.pda.PdaFeignClient;
import com.ding.pda.constant.PdaConstant;
import com.ding.pda.entity.Pda;
import com.ding.pda.mapper.PdaMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hs.car.mapper.CarMapper;
import com.hs.car.pojo.Car;
import com.hs.common.api.dto.ResultCode;
import com.hs.common.api.dto.ResultVo;
import com.hs.device.entity.Detector;
import com.hs.device.mapper.DetectorMapper;
import com.hs.jwt.JwtTemplate;
import com.hs.order.mapper.OrdersMapper;
import com.hs.order.pojo.Orders;
import com.hs.pk.berth.bean.Road;
import com.hs.pk.berth.mapper.RoadMapper;
import com.hu.pk.patroller.constans.DeviceConstant;
import com.hu.pk.patroller.constans.OrderConstant;
import com.hu.pk.patroller.constans.PatrollerConstant;
import com.hu.pk.patroller.constans.RedisConstant;
import com.hu.pk.patroller.dto.OrderDto;
import com.hu.pk.patroller.dto.PatrollerrDto;
import com.hu.pk.patroller.entity.Patroller;
import com.hu.pk.patroller.exception.Asserts;
import com.hu.pk.patroller.mapper.PatrollerMapper;
import com.hu.pk.patroller.service.IPatrollerService;
import com.hu.pk.patroller.vo.ChargesOrderVo;
import com.hu.pk.patroller.vo.ClaimedOrderVo;
import com.hu.pk.patroller.vo.UnclaimedBerthDetailVo;
import com.hu.pk.patroller.vo.UnclaimedOrderVo;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.*;

/**
 * <p>
 * 巡检 服务实现类
 * </p>
 *
 * @author Hu
 * @since 2022-07-20
 */
@Service
class PatrollerServiceImpl extends ServiceImpl<PatrollerMapper, Patroller> implements IPatrollerService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private JwtTemplate jwtTemplate;

    @Autowired
    private RoadMapper roadMapper;

    @Autowired
    private PatrollerMapper patrollerMapper;

    @Autowired
    private PdaFeignClient pdaFeignClient;
    
    @Autowired
    private PdaMapper pdaMapper;

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private CarMapper carMapper;

    @Autowired
    private DetectorMapper detectorMapper;
    
    
    @Override
    public String login(PatrollerrDto patrollerrDto) {
        LambdaQueryWrapper<Patroller> wrapper = Wrappers.lambdaQuery(Patroller.class);
        wrapper.eq(Patroller::getTelephone,patrollerrDto.getTelephone());
        Patroller patroller = this.getOne(wrapper);
        //1 电话号码（即用户名）校验
        if(ObjectUtils.isEmpty(patroller)){
            Asserts.failed("用户名或密码不存在");
        }
        //2 密码校验
        if (!BCrypt.checkpw(patrollerrDto.getPassword(),patroller.getPassword())){
            // 密码校验失败
            Asserts.failed("用户名或密码不存在！");
        }
        //3、校验成功，生成token
        Map<String,Object> playload = new HashMap<>();
        playload.put(PatrollerConstant.PATROLLER_ID,patroller.getId());
        String token = jwtTemplate.createToken(playload);

        //4、token存储到redis中，设置有效时间
        redisTemplate.opsForValue().set(
                RedisConstant.PATROLLER_TOKEN +patroller.getId(),token, Duration.ofMinutes(30));

        //绑定pda与巡检员账号
        Long id = patroller.getId();
        LambdaQueryWrapper<Pda> lq= Wrappers.lambdaQuery(Pda.class);
        lq.eq(Pda::getPatrollerId,patroller.getId());
        Pda pda = pdaMapper.selectOne(lq);
        ResultVo resultVo = pdaFeignClient.bindPda(pda.getId(), patroller.getId(), PdaConstant.PDA_INTLINE);

        //5、返回token
        return token;
    }

    @Override
    public Long selectRoadIdByPatrollerName(String patrollerName) {
        LambdaQueryWrapper<Patroller> lqw = Wrappers.lambdaQuery(Patroller.class);
        lqw.eq(Patroller::getName,patrollerName);
        lqw.select(Patroller::getRoadId);
        Patroller one = this.getOne(lqw);
        return one.getRoadId();
    }

    @Override
    public ResultVo selectUnclaimedOrder() throws ParseException {

        //拿到redis中全部未认领的订单
        Map<String, OrderDto> entries = redisTemplate.opsForHash().entries("unclaimed");

        //确定时间显示的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //创建用来储存返回给前端的数据的集合，
        List<UnclaimedOrderVo> list = new ArrayList<>();

        //遍历输出map中的对象
        for (Map.Entry<String, OrderDto> entry : entries.entrySet()) {

            //先拿到map集合中的单个对象
            OrderDto dto = entry.getValue();

            //创建返回vo对象
            UnclaimedOrderVo vo = new UnclaimedOrderVo();

            //把返回给前端的vo对象中需要的数据，从由redis中拿到的未认领订单数据dto"复制"给它。
            //copyProperties方法只把vo中有的字段从dto中复制过来
            BeanUtils.copyProperties(dto,vo);

            //计算当下时间与驶入时间的时间差，并转换为具体的几分几秒
            String driveInTimeFormat = sdf.format(dto.getDriveInTime());
            String currentTime = sdf.format(new Date());
            Date date1 = sdf.parse(driveInTimeFormat);
            Date date2 = sdf.parse(currentTime);
            Long diff=date2.getTime()-date1.getTime();
            long minutes=(diff/1000)/60;
            long seconds=(diff/1000)%60;
            vo.setEnterTime(minutes+":"+seconds);
            list.add(vo);
        }
        return new ResultVo(list);
/*
        Date driveInTime = (Date) redisTemplate.opsForHash().get("unclaimed:road:berth:", "driveInTime");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String driveInTimeFormat = sdf.format(driveInTime);
        String currentTime = sdf.format(new Date());
        UnclaimedOrderVo unclaimedOrderVo = new UnclaimedOrderVo();
        try {
            Date date1 = sdf.parse(driveInTimeFormat);
            Date date2 = sdf.parse(currentTime);
            Long diff=date2.getTime()-date1.getTime();
            long minutes=(diff/1000)/60;
            long seconds=(diff/1000)%60;
            unclaimedOrderVo.setRoadId(roadId);
            unclaimedOrderVo.setBerthId(berthId);
            unclaimedOrderVo.setEnterTime(minutes+":"+seconds);
        } catch (ParseException e) {
            e.printStackTrace();
        }
*/
    }

    @Override
    public ResultVo selectUnclaimedBerthDetail(Long roadId, Long berthId) {
        //通过道路编号与泊车位编号查询redis中泊车位的具体详情
        OrderDto orderDto = (OrderDto) redisTemplate.opsForHash().get("unclaimed", "unclaimed:road" + roadId + ":berth:" + berthId);

        if(ObjectUtils.isEmpty(orderDto)){
            return new ResultVo(ResultCode.RESULE_DATA_NONE);
        }
        UnclaimedBerthDetailVo unclaimedBerthDetailVo = new UnclaimedBerthDetailVo();

        LambdaQueryWrapper<Road> wrapper = Wrappers.lambdaQuery(Road.class);
        wrapper.eq(Road::getId,orderDto.getRoadId());
        wrapper.select(Road::getName);
        Road road = roadMapper.selectOne(wrapper);

        unclaimedBerthDetailVo.setRoadName(road.getName());
        unclaimedBerthDetailVo.setOrderStatus(OrderConstant.ORDER_STATUS_UNCLAIM);
        //复制
        BeanUtils.copyProperties(orderDto,unclaimedBerthDetailVo);

        return new ResultVo(unclaimedBerthDetailVo);
    }

    @Override
    public ResultVo bindCarAndBerth(Long roadId,Long berthId,String carLicensePlate,Long patrollerId,String userTel) {
        if(!StringUtils.hasText(carLicensePlate)){
            return new ResultVo(ResultCode.PARAM_IS_BLANK);
        }
        //1.修改订单状态，绑定泊车位与车牌
        redisTemplate.opsForHash().put("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId,"carLicensePlate",carLicensePlate);
        redisTemplate.opsForHash().put("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId,"status", OrderConstant.ORDER_STATUS_CLAIM);
        redisTemplate.opsForHash().put("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId,"userTel", userTel);

        //2.返回订单部分信息给前端
        ClaimedOrderVo claimedOrderVo = new ClaimedOrderVo();

        //2.1订单编号
        Long id = Long.valueOf((int) redisTemplate.opsForHash().get("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId, "id"));

        //2.2停车道路名称
        LambdaQueryWrapper<Road> wrapper = Wrappers.lambdaQuery(Road.class);
        wrapper.eq(Road::getId,roadId);
//        wrapper.select(Road::getName);
        Road road = roadMapper.selectOne(wrapper);

        //2.3驶入时间
        Date driveInTime = (Date) redisTemplate.opsForHash().get("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId, "driveInTime");


        //2.4车牌号码
        String carLicensePlate1 = (String) redisTemplate.opsForHash().get("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId, "carLicensePlate");

        //2.5录入者姓名
        LambdaQueryWrapper<Patroller> queryWrapper = Wrappers.lambdaQuery(Patroller.class);
        queryWrapper.eq(Patroller::getId,patrollerId);
//        queryWrapper.select(Patroller::getName);
        Patroller patroller = patrollerMapper.selectById(patrollerId);

        //2.6查询电话号码
        LambdaQueryWrapper<Car> lambdaQuery = Wrappers.lambdaQuery(Car.class);
        lambdaQuery.eq(Car::getLicensePlate,carLicensePlate);
        Car car = carMapper.selectOne(lambdaQuery);


        claimedOrderVo.setOrderId(id);
        claimedOrderVo.setRoadName(road.getName());
        claimedOrderVo.setBerthId(berthId);
        claimedOrderVo.setOrderStatus(OrderConstant.ORDER_STATUS_CLAIM);
        claimedOrderVo.setDriveinTime(driveInTime.toString());
        claimedOrderVo.setCarLicensePlate(carLicensePlate1);
        claimedOrderVo.setPatrollerName(patroller.getName());
        claimedOrderVo.setPhoneNum(car.getTelephone());


        //3.把redis已认领的订单从未认领的订单表中删除
        Long unclaimed = redisTemplate.opsForHash().delete("unclaimed", "unclaimed:road" + roadId + ":berth:" + berthId);

        return new ResultVo(claimedOrderVo);
    }

    @Override
    public ResultVo departureAndCharges(String carLicensePlate) {
        LambdaQueryWrapper<Orders> wrapper = Wrappers.lambdaQuery(Orders.class);
        wrapper.eq(Orders::getCarLicensePlate,carLicensePlate);
        Orders orders = ordersMapper.selectOne(wrapper);
        ChargesOrderVo chargesOrderVo = new ChargesOrderVo();
        BeanUtils.copyProperties(orders,chargesOrderVo);

        return new ResultVo(chargesOrderVo);
    }

    @Override
    public ResultVo findOrderByStatus(Integer orderStatus,Integer allOrders) {
        List<Orders> orders=new ArrayList<>();
        if(orderStatus==OrderConstant.ORDER_STATUS_UNPAY||allOrders==8){
            LambdaQueryWrapper<Orders> wrapper = Wrappers.lambdaQuery(Orders.class);
            wrapper.eq(Orders::getStatus,OrderConstant.ORDER_STATUS_UNPAY);
            orders = ordersMapper.selectList(wrapper);

        }
        if(orderStatus==OrderConstant.ORDER_STATUS_PAY||allOrders==8){
            LambdaQueryWrapper<Orders> wrapper = Wrappers.lambdaQuery(Orders.class);
            wrapper.eq(Orders::getStatus,OrderConstant.ORDER_STATUS_PAY);
            orders = ordersMapper.selectList(wrapper);

        }
        if(orderStatus==OrderConstant.ORDER_STATUS_FINISH||allOrders==8){
            LambdaQueryWrapper<Orders> wrapper = Wrappers.lambdaQuery(Orders.class);
            wrapper.eq(Orders::getStatus,OrderConstant.ORDER_STATUS_FINISH);
            orders = ordersMapper.selectList(wrapper);

        }
        if(orderStatus==OrderConstant.ORDER_STATUS_CLAIM||allOrders==8){
            LambdaQueryWrapper<Detector> wrapper = Wrappers.lambdaQuery(Detector.class);
            wrapper.eq(Detector::getHaveCar, DeviceConstant.DEVICE_STATUS_IN);
            List<Detector> detectors = detectorMapper.selectList(wrapper);
            ObjectMapper objectMapper = new ObjectMapper();
            for(Detector detector:detectors){
                Long roadId = detector.getRoadId();
                Long berthId = detector.getBerthId();
                Map<String,String> entries = redisTemplate.opsForHash().entries("tempOrder:" + "roadId:" + roadId + ":berthId:" + berthId);
                Orders order = objectMapper.convertValue(entries, Orders.class);
                if(order.getStatus()==OrderConstant.ORDER_STATUS_CLAIM){
                    orders.add(order);
                }
            }
        }
        return new ResultVo(orders);
    }

    @Override
    public ResultVo findBerthByStatus() {

        return null;
    }

    public static void main(String[] args) {
        String gensalt = BCrypt.gensalt();
        System.out.println("gensalt = " + gensalt);

        String hashpw = BCrypt.hashpw("123456", gensalt);
        System.out.println("hashpw = " + hashpw);

        boolean checkpw = BCrypt.checkpw("123456", hashpw);
        System.out.println("checkpw = " + checkpw);

    }


}
